package com.swotxu.oldwebproject.session.listener.filter;

import com.swotxu.oldwebproject.redis.RedisManager;
import com.swotxu.oldwebproject.redis.connection.IRedisConnection;
import com.swotxu.oldwebproject.session.RedisSessionRepository;
import com.swotxu.oldwebproject.session.handler.SessionAttributeHandler;
import com.swotxu.oldwebproject.session.listener.session.RedisSessionAttributeListener;
import com.swotxu.oldwebproject.session.utils.RedisSessionUtil;
import com.swotxu.oldwebproject.utils.SessionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpSession;
import java.util.*;

/**
 * 请求结束前，将缓存的 Session 数据，刷回 Redis，保证数据一致
 *
 * @Date: 2021/3/25 0025 14:11
 * @Author: swotxu
 */
public class RefreshSessionAttrFilterListener implements RedisSessionFilterListener {
    private static final Logger LOGGER = LoggerFactory.getLogger(RefreshSessionAttrFilterListener.class);

    private static IRedisConnection connection = RedisManager.getIRedisConnection();
    private static RedisSessionRepository repository = new RedisSessionRepository(connection);

    @Override
    public void doFilterBefore(RedisFilterEvent event) {
        SessionAttributeHandler.removeAll();
    }

    @Override
    public void doFilterAfter(RedisFilterEvent event) {
        refreshSessionAttr();
    }

    @Override
    public int fliterOrder() {
        return -40;
    }

    private void refreshSessionAttr() {
        Set<String> sessionIds = SessionAttributeHandler.getKeys();
        LOGGER.info("refresh sessionIds: {}", sessionIds);
        if (CollectionUtils.isEmpty(sessionIds)) {
            return;
        }
        // 依次回刷每个 session
        for (String sessionId : sessionIds) {
            refreshSessionAttr(sessionId);
        }
        // 清空线程缓存
        SessionAttributeHandler.removeAll();
    }

    private void refreshSessionAttr(String sessionId) {
        String sessionKey = RedisSessionUtil.getSessionKey(sessionId);

        if (!connection.exists(sessionKey)) {
            LOGGER.info("[{}] is invalid!", sessionKey);
            return;
        }
        Map<String, Object> fieldMap = SessionAttributeHandler.getFieldMap(sessionId);
        LOGGER.info("session: {} -> {}", sessionId, fieldMap);
        if (CollectionUtils.isEmpty(fieldMap)) {
            LOGGER.info("[{}] Fields is Empty!", sessionId);
            return;
        }
        Set<Map.Entry<String, Object>> entries = fieldMap.entrySet();
        // 批量回刷属性集
        Map<String, Object> refreshMap = new HashMap<>(entries.size(), 1.0f);
        // 批量删除属性集
        List<String> delList = new ArrayList<>(entries.size()/2 +1);
        for (Map.Entry<String, Object> entry : entries) {
            handleAttr(sessionId, refreshMap, delList, entry);
        }
        LOGGER.info("批量回刷结果[{}]! fields: {}", connection.hmset(sessionKey, refreshMap), refreshMap);
        LOGGER.info("批量删除结果[{}]! fields: {}", connection.hdel(sessionKey, delList.toArray(new String[delList.size()])), delList);
    }

    private void handleAttr(String sessionId, Map<String, Object> refreshMap, List<String> delList, Map.Entry<String, Object> entry) {
        String fieldKey = RedisSessionUtil.getSessionAttrField(entry.getKey());
        Object value = entry.getValue();

        if (RedisSessionAttributeListener.METHOD_ISNEW.equals(entry.getKey())) {
            return;
        }
        if (value == null) {
            delList.add(fieldKey);
        } else if (SessionUtil.KEY_USERINFO.equals(entry.getKey())) {
            HttpSession session = repository.getSession(sessionId, null, false);
            if (session != null) {
                session.setAttribute(SessionUtil.KEY_USERINFO, value);
            }
        } else {
            refreshMap.put(fieldKey, value);
        }
    }
}
